/********************************************************************
 *@brief Implement a universal variable class
 *@author wcf
 *@date 2025-01-10
********************************************************************/

#ifndef __CS_VARIANT_H__
#define __CS_VARIANT_H__

#include "cscoreglobal.h"

CS_NAMESPACE_BEGIN

class csVariant;
using csVariantMap = csMap<csString, csVariant>;
class CSCORE_EXPORT csVariant
{
public:
	csVariant() : m_data() {}
	csVariant(char c);
	csVariant(unsigned char uc);
	csVariant(short s);
	csVariant(signed char sc);
	csVariant(unsigned short us);
	csVariant(int i);
	csVariant(unsigned int ui);
	csVariant(long l);
	csVariant(unsigned long ul);
	csVariant(long long ll);
	csVariant(unsigned long long ull);
	csVariant(bool b);
	csVariant(double d);
	csVariant(float f);
	~csVariant() { }
	template <typename T>
	T value() const;
	template <typename T>
	void setValue(const T& value);
	template <typename T>
	inline static csVariant fromValue(const T& value);
	char toChar() const;
	unsigned char toUChar() const;
	short toShort() const;
	signed char toSChar() const;
	unsigned short toUShort() const;
	int toInt() const;
	unsigned int toUInt() const;
	long toLong() const;
	unsigned long toULong() const;
	long long toLongLong() const;
	unsigned long long toULongLong() const;
	bool toBool() const;
	double toDouble() const;
	float toFloat() const;
private:
	union Data
	{
		char c;
		unsigned char uc;
		short s;
		signed char sc;
		unsigned short us;
		int i;
		unsigned int ui;
		long l;
		unsigned long ul;
		long long ll;
		unsigned long long ull;
		bool b;
		double d;
		float f;
	} m_data;
};

template <typename T>
T csVariant::value() const
{
	auto& typeidT = typeid(T);
	if (typeidT == typeid(char))
		return m_data.c;
	else if (typeidT == typeid(unsigned char))
		return m_data.uc;
	else if (typeidT == typeid(short))
		return m_data.s;
	else if (typeidT == typeid(signed char))
		return m_data.sc;
	else if (typeidT == typeid(unsigned short))
		return m_data.us;
	else if (typeidT == typeid(int))
		return m_data.us;
	else if (typeidT == typeid(unsigned int))
		return m_data.ui;
	else if (typeidT == typeid(long))
		return m_data.l;
	else if (typeidT == typeid(unsigned long))
		return m_data.ul;
	else if (typeidT == typeid(long long))
		return m_data.ll;
	else if (typeidT == typeid(unsigned long long))
		return m_data.ull;
	else if (typeidT == typeid(bool))
		return m_data.b;
	else if (typeidT == typeid(double))
		return m_data.d;
	else if (typeidT == typeid(float))
		return m_data.f;
	return T();
}

template <typename T>
void csVariant::setValue(const T& value)
{
	auto& typeidT = typeid(T);
	if (typeidT == typeid(char))
		m_data.c = value;
	else if (typeidT == typeid(unsigned char))
		m_data.uc = value;
	else if (typeidT == typeid(short))
		m_data.s = value;
	else if (typeidT == typeid(signed char))
		m_data.sc = value;
	else if (typeidT == typeid(unsigned short))
		m_data.us = value;
	else if (typeidT == typeid(int))
		m_data.i = value;
	else if (typeidT == typeid(unsigned int))
		m_data.ui = value;
	else if (typeidT == typeid(long))
		m_data.l = value;
	else if (typeidT == typeid(unsigned long))
		m_data.ul = value;
	else if (typeidT == typeid(long long))
		m_data.ll = value;
	else if (typeidT == typeid(unsigned long long))
		m_data.ull = value;
	else if (typeidT == typeid(bool))
		m_data.b = value;
	else if (typeidT == typeid(double))
		m_data.d = value;
	else if (typeidT == typeid(float))
		m_data.f = value;
	else
		;// setData(&value, typeid(T));
}

template <typename T>
inline static csVariant csVariant::fromValue(const T& value)
{
	csVariant variant;
	variant.setValue(value);
	return variant;
}

CS_NAMESPACE_END

#endif // !__CS_VARIANT_H__
